package com.lzy.mall.product.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.lzy.mall.common.constant.Constant;
import com.lzy.mall.common.utils.PageParaUtils;
import com.lzy.mall.common.utils.PageUtils;
import com.lzy.mall.common.utils.ResultUtils;
import com.lzy.mall.common.vo.AddToCartVo;
import com.lzy.mall.product.dao.PmsSkuInfoDao;
import com.lzy.mall.product.dao.PmsSkuSaleAttrValueDao;
import com.lzy.mall.product.entity.PmsSkuImages;
import com.lzy.mall.product.entity.PmsSkuInfo;
import com.lzy.mall.product.entity.PmsSkuSaleAttrValue;
import com.lzy.mall.product.entity.PmsSpuInfoDesc;
import com.lzy.mall.product.feign.SeckillFeignService;
import com.lzy.mall.product.service.*;
import com.lzy.mall.product.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.beetl.sql.core.engine.PageQuery;
import org.beetl.sql.core.query.LambdaQuery;
import org.springframework.stereotype.Service;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;


/**
 * sku信息(PmsSkuInfo)表服务实现类
 *
 * @author lzy
 * @since 2021-08-25 11:41:20
 */
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
@Slf4j
public class PmsSkuInfoServiceImpl implements PmsSkuInfoService {
    private final PmsSkuInfoDao skuInfoDao;

    private final PmsSkuImagesService skuImagesService;

    private final PmsSpuInfoDescService spuInfoDescService;

    private final PmsAttrGroupService attrGroupService;

    private final PmsSkuSaleAttrValueService skuSaleAttrValueService;

    private final PmsSkuSaleAttrValueDao skuSaleAttrValueDao;

    private final ThreadPoolExecutor executor;

    private final SeckillFeignService seckillFeignService;

    @Override
    public Long save(PmsSkuInfo skuInfo) {
        skuInfoDao.insertTemplate(skuInfo,true);
        return skuInfo.getSkuId();
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        LambdaQuery<PmsSkuInfo> lambdaQuery = skuInfoDao.createLambdaQuery();

        String key = (String) params.get("key");
        //where  (id=1 or spu_name like xxx)
        if(StrUtil.isNotEmpty(key)){
            lambdaQuery.and(
                    lambdaQuery.condition()
                            .andEq(PmsSkuInfo::getSkuId,key)
                            .orLike(PmsSkuInfo::getSkuName,key));
        }

        String catelogId = (String) params.get("catelogId");
        if(StrUtil.isNotEmpty(catelogId) && !Constant.ALL_LIST_ID.equalsIgnoreCase(catelogId)){
            lambdaQuery.andEq(PmsSkuInfo::getCatalogId,catelogId);
        }

        String brandId = (String) params.get("brandId");
        if(StrUtil.isNotEmpty(brandId) && !Constant.ALL_LIST_ID.equalsIgnoreCase(brandId)){
            lambdaQuery.andEq(PmsSkuInfo::getBrandId,brandId);
        }

        String min = (String) params.get("min");
        if(StrUtil.isNotEmpty(min)){
            lambdaQuery.andGreatEq(PmsSkuInfo::getPrice,min);
        }

        String max = (String) params.get("max");
        if(StrUtil.isNotEmpty(max)){
            try {
                BigDecimal decimal = new BigDecimal(max);
                if (decimal.compareTo(BigDecimal.ZERO) == 1){
                    lambdaQuery.andLessEq(PmsSkuInfo::getPrice,max);
                }
            } catch (Exception e) {
            }
        }
        PageQuery pageQuery = PageParaUtils.pagePara(params);
        PageQuery<PmsSkuInfo> page = lambdaQuery.page(pageQuery.getPageNumber(), pageQuery.getPageSize());
        return new PageUtils(page);
    }

    @Override
    public List<PmsSkuInfo> getSkuBySpuId(Long spuId) {
        List<PmsSkuInfo> select = skuInfoDao.createLambdaQuery()
                .andEq(PmsSkuInfo::getSpuId, spuId)
                .select();
        return select;
    }

    @Override
    public SkuItemVo item(Long skuId) {
        SkuItemVo vo = new SkuItemVo();

        CompletableFuture<PmsSkuInfo> infoFuture = CompletableFuture.supplyAsync(() -> {
            //1.sku的基本信息获取 pms_sku_info
            PmsSkuInfo skuInfo = skuInfoDao.single(skuId);
            vo.setInfo(skuInfo);
            return skuInfo;
        }, executor);


        CompletableFuture<Void> imagesFuture = CompletableFuture.runAsync(() -> {
            //2.sku的图片信息  pms_sku_images
            List<PmsSkuImages> skuImages = skuImagesService.getBySkuId(skuId);
            vo.setImages(skuImages);
        }, executor);

        CompletableFuture<Void> saleAttrFuture = infoFuture.thenAcceptAsync((res) -> {
            //3.获取spu的销售属性组合
            List<ItemSaleAttrDataVo> saleAttrDataVos = skuSaleAttrValueService.getSaleAttrsBySpuId(res.getSpuId());

            List<ItemSaleAttrVo> saleAttrVos = new ArrayList<>();
            saleAttrDataVos.forEach(item -> {
                ItemSaleAttrVo attrVo = new ItemSaleAttrVo();
                AttrValueWithSkuIdVo skuIdVo = new AttrValueWithSkuIdVo();
                skuIdVo.setAttrValue(item.getAttrValue());
                skuIdVo.setSkuIds(item.getSkuIds());

                attrVo.setAttrId(item.getAttrId());
                attrVo.setAttrName(item.getAttrName());
                //TODO 不需要使用list
                attrVo.setAttrValues(CollUtil.toList(skuIdVo));

                saleAttrVos.add(attrVo);
            });
            System.out.println(saleAttrDataVos);
            vo.setSaleAttr(saleAttrVos);
        }, executor);

        CompletableFuture<Void> spuInfoDescFuture = infoFuture.thenAcceptAsync((res) -> {
            //4.获取spu的介绍
            PmsSpuInfoDesc spuInfoDesc = spuInfoDescService.getById(res.getSpuId());
            vo.setDesc(spuInfoDesc);
        }, executor);

        CompletableFuture<Void> groupAttrsFuture = infoFuture.thenAcceptAsync((res) -> {
            //5.获取spu的规格参数信息
            List<SpuItemAttrGroup> groupAttrs = attrGroupService.getAttrGroupWithAttrsBySpuId(res.getSpuId(), res.getCatalogId());
            List<SpuItemAttrGroupVo> collect = groupAttrs.stream().map(g -> {
                SpuItemAttrGroupVo itemVo = new SpuItemAttrGroupVo();
                itemVo.setGroupName(g.getGroupName());
                List<Attr> attrs = new ArrayList<>();
                Attr attr = new Attr();
                attr.setAttrName(g.getAttrName());
                attr.setAttrValue(g.getAttrValue());
                attrs.add(attr);
                itemVo.setAttrs(attrs);
                return itemVo;
            }).collect(Collectors.toList());
            vo.setGroupAttrs(collect);
        }, executor);

        //查询是否参与秒杀
        CompletableFuture<Void> seckillFuture = CompletableFuture.runAsync(() -> {
            ResultUtils result = seckillFeignService.getSkuSeckillInfo(skuId);
            if (result.getCode() == 0) {
                SeckillInfoVo seckillInfoVo = (SeckillInfoVo) result.getBean(SeckillInfoVo.class);
                vo.setSeckillInfoVo(seckillInfoVo);
            }
        }, executor);


        try {
            CompletableFuture.allOf(imagesFuture,saleAttrFuture,spuInfoDescFuture,groupAttrsFuture,seckillFuture).get();
        } catch (Exception e) {
            log.info("异步编排异常，原因：{}",e);
        }
        return vo;
    }

    @Override
    public PmsSkuInfo getById(Long skuId) {
        return skuInfoDao.single(skuId);
    }

    @Override
    public Long getSkuIdByAttr(AddToCartVo vo) {

        PmsSkuInfo single = skuInfoDao.single(vo.getSkuId());
        List<Long> list1 = skuInfoDao.createLambdaQuery()
                .andEq(PmsSkuInfo::getSpuId, single.getSpuId())
                .select()
                .stream()
                .map(PmsSkuInfo::getSkuId)
                .collect(Collectors.toList());

        List<String> attrValues = vo.getAttrValues();
        final List<Long>[] skuId = new List[]{new ArrayList<>(list1)};
        attrValues.forEach(a -> {
            List<Long> collect = skuSaleAttrValueDao
                    .createLambdaQuery()
                    .andEq(PmsSkuSaleAttrValue::getAttrValue, a)
                    .select()
                    .stream()
                    .map(PmsSkuSaleAttrValue::getSkuId)
                    .collect(Collectors.toList());
            skuId[0] = (List<Long>) CollUtil.intersection(skuId[0], collect);
        });
        return skuId[0].get(0);
    }
}
